﻿using System;
using System.Collections.Generic;
using Kristall;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Xml.Serialization;
using Kristall.MyGame.Projectiles;
using Kristall.Engine;
using Kristall.Managers;

namespace Kristall
{
    public class Player : Actor
    {
        public override float MoveAcceleration
        {
            get
            {
                return Kristall.Options.player_speed;
            }
        }

        public override float GroundDragFactor
        {
            get
            {
                return Kristall.Options.ground_drag;
            }
        }

        public override float JumpLaunchVelocity
        {
            get
            {
                return Kristall.Options.jump_vel;
            }
        }

        public override float MaxMoveSpeed
        {
            get
            {
                return Kristall.Options.max_speed;
            }
        }

        public override float MaxJumpTime
        {
            get
            {
                return Kristall.Options.jump_time;
            }
        }


        public CrystalType EnergyType = CrystalType.None;
        public Crystal Crystal;

        public Vector2 LookDirection = Vector2.UnitX;
        public Vector2 VerticalLookDirection = Vector2.Zero;
        AnimatableSprite runAnimation; 
        AnimatableSprite idleAnimation;

        string run = @"Player\Run.xnb";
        string idle = @"Player\Idle.xnb";

        [XmlIgnore]
        Animatable _energyOrb;

        [XmlIgnore]
        public Light FollowLight;

        public Vector2 CheckPoint
        {
            get;
            set;
        }

        private float followLightSize
        {
            get
            {
                return Kristall.Options.fl_size * MathHelper.Clamp(Health, 0, 1f);
            }
        }

        public override float Health
        {
            get
            {
                return base.Health;
            }
            set
            {
                //We've lost health (taken damage)
                if (Health > value)
                {
                    //We haven't been stunned
                    if (StunTimer >= StunTime)
                    {
                        base.Health = value;
                        Kristall.SoundManager.PlayNonInstancedSound("PlayerHit");
                    }
                }
                else
                {
                    base.Health = value;
                }
            }
        }
        Vector2 _energyOrbOffset;

        public Weapon CurrentWeapon { get; set; }

        public void Respawn()
        {
            Position = CheckPoint;
            _energyOrb.Position = Position + _energyOrbOffset;

            Velocity = Vector2.Zero;

            Health = 1.0f;
            StunTimer = StunTime;
        }

        public override void LoadContent(Level level)
        {
            runAnimation = new AnimatableSprite(run);
            idleAnimation = new AnimatableSprite(idle);

            Animations.Add(idleAnimation);
            Animations.Add(runAnimation);

            LayerDepth = 0.5f;

            base.LoadContent(level);

            CurrentAnimationKey = idle;

            runAnimation.FrameCount = 4;
            runAnimation.FrameHeight = 128;
            runAnimation.FrameWidth = 100;
            runAnimation.Scale *= 40f / 100f;

            idleAnimation.FrameWidth = 100; //frameSize;
            idleAnimation.FrameHeight = 128;
            idleAnimation.Scale *= 40f / 100f;

            runAnimation.IsLooping = true;

            this.CheckWorldCollision = true;
            this.CheckPlayerCollision = false;

            StunTime = 0.5f;
            StunBlinkRate = 3f;

            this.SetSize(40, 40); //frameSize, frameSize
            runAnimation.Origin = idleAnimation.Origin = new Vector2(16, 30);

            _energyOrb = new Animatable();
            string orb = @"Player\EnergyOrb.xnb";
            _energyOrb.Animations.Add(new AnimatableSprite(orb));
            _energyOrb.CurrentAnimationKey = orb;
            _energyOrb.LoadContent(level);
            _energyOrb.Width = _energyOrb.Height = 24;
            _energyOrbOffset = Vector2.UnitY * -_energyOrb.Height + Vector2.UnitX * -4;
            _energyOrb.CurrentAnimation.FrameWidth = _energyOrb.CurrentAnimation.FrameHeight = 48;
            _energyOrb.CurrentAnimation.Scale = Vector2.One * _energyOrb.Width / 48;
            _energyOrb.LayerDepth = 0.5f;

            FollowLight = new Light();
            updateFollowLight();

            this.EnergyType = CrystalType.None;
        }

        public void HandleInput(InputState input)
        {
            if (input.CurrentKeyboardStates.IsKeyDown(Keys.Left) || input.CurrentKeyboardStates.IsKeyDown(Keys.A))
            {
                Movement = LookDirection = - Vector2.UnitX;
                runAnimation.Mirror = idleAnimation.Mirror = false;
            }
            else if (input.CurrentKeyboardStates.IsKeyDown(Keys.Right) || input.CurrentKeyboardStates.IsKeyDown(Keys.D))
            {
                Movement = LookDirection = Vector2.UnitX;
                runAnimation.Mirror = idleAnimation.Mirror = true;
            }

            VerticalLookDirection = Vector2.Zero;
            if (input.CurrentKeyboardStates.IsKeyDown(Keys.Up) || input.CurrentKeyboardStates.IsKeyDown(Keys.W))
            {
                VerticalLookDirection = -Vector2.UnitY;
            }
            else if (input.CurrentKeyboardStates.IsKeyDown(Keys.Down) || input.CurrentKeyboardStates.IsKeyDown(Keys.Down))
            {
                VerticalLookDirection = Vector2.UnitY;
            }

            if(CurrentWeapon != null)
                CurrentWeapon.HandleInput(input);


            if (input.CurrentKeyboardStates.IsKeyDown(Keys.Space)) //input.IsKeyPressed(Keys.Space)) // && IsOnGround
            {
                IsJumping = true;
                if(IsOnGround && input.LastKeyboardStates.IsKeyUp(Keys.Space))
                    Kristall.SoundManager.PlayNonInstancedSound("Jump");
            }
        }

        void updateFollowLight()
        {
            FollowLight.SetSize(Kristall.Viewport * followLightSize);
            FollowLight.Position = this.Center - Kristall.Viewport * followLightSize * 0.5f;

            //FollowLight.Color = Color.White * Kristall.Options.follow_light;
            FollowLight.Color = Color.White * Kristall.Options.fl_intensity;
            FollowLight.Color = Color.Lerp(FollowLight.Color, Color.Red, 1.0f - Health);
        }

        void updateEnergyOrb(float dt)
        {
            float damping = Kristall.Options.eo_damping; // 600.0f;
            float stiffness = Kristall.Options.eo_stiffness; //1000.0f;
            float mass = Kristall.Options.eo_mass; //50f;

            Vector2 target = Position + _energyOrbOffset;

            // Calculate spring force
            Vector2 stretch = _energyOrb.Position - target;
            Vector2 force = -stiffness * stretch - damping * _energyOrb.Velocity;

            // Apply acceleration
            Vector2 acceleration = force / mass;
            _energyOrb.Velocity += acceleration * dt;

            _energyOrb.Position += _energyOrb.Velocity * dt;

            _energyOrb.Update(dt);

            if (Crystal != null && (EnergyType == CrystalType.None || EnergyType == Crystal.Type))
            {
                if (!Crystal.Drained) //Crystal.Energy > 0
                {
                    //If the crystal is not drained, tint with linear interpolation between White
                    _energyOrb.CurrentAnimation.Tint = Color.Lerp(Color.White, Crystal.GetColor(), (1 - Crystal.Energy));
                }
                else if(EnergyType != CrystalType.None)
                {
                    _energyOrb.CurrentAnimation.Tint = Color.Lerp(Color.White, Crystal.GetColor(), (1 - Crystal.Energy));
                }
            }

            //Crystal = null;
        }

        public override void Update(float dt)
        {
            if (IsAlive)
            {
                if (Math.Abs(Velocity.X) > 20f || !Movement.Equals(Vector2.Zero))
                {
                    CurrentAnimationKey = run;
                }
                else
                {
                    CurrentAnimationKey = idle;
                }
            }

            updateFollowLight();
            updateEnergyOrb(dt);

            if(CurrentWeapon != null)
                CurrentWeapon.UpdateWeapon(dt);

            if(Health < 1.0f)
                Health += dt * Kristall.Options.regen;

            base.Update(dt);
        }

        public override void Draw(SpriteBatch batch)
        {
            base.Draw(batch);

            _energyOrb.Draw(batch);
        }
    }
}
